package club.kingyin.easycache.component.annotation.handler;

import club.kingyin.easycache.cache.AbstractCache;
import club.kingyin.easycache.component.CachePostProcess;
import club.kingyin.easycache.component.PostProcess;
import club.kingyin.easycache.component.Timer;
import club.kingyin.easycache.component.annotation.CacheHandler;
import club.kingyin.easycache.exception.InitException;
import club.kingyin.easycache.method.CacheMethod;
import club.kingyin.easycache.utils.InstanceUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;

/**
 * 缓存后置处理器注册模块，是首个处理器且必须存在
 * 否则CacheHandler注解将无法生效，即自定性处理器无法加载至当前缓存流程
 */
@Slf4j
public class AnnotationCacheCustomizationPostProcess implements CachePostProcess {

    @Override
    public void postProcessBeforeSetCache(CacheMethod invocation, Object value, Timer timer) {
        if (invocation.getMethod().isAnnotationPresent(CacheHandler.class)) {
            CacheHandler handler = invocation.getMethod().getDeclaredAnnotation(CacheHandler.class);
            try {
                CachePostProcess process = (CachePostProcess) PostProcessFactory.acpps.getOrDefault(handler.value(), (CachePostProcess) InstanceUtils.newInstance(handler.value()));
                log.debug("方法：[{}] 装载CacheHandler {}", invocation.getMethod().getName(), process);
                if (handler.overall()) {
                    PostProcessFactory.overall.add(process);
                    for (PostProcess postProcess : PostProcessFactory.overall) {
                        if (postProcess instanceof CachePostProcess)
                            ((CachePostProcess) postProcess).postProcessBeforeSetCache(invocation, value, timer);
                    }
                } else {
                    process.postProcessBeforeSetCache(invocation, value, timer);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                // 初始化实例失败
                throw new InitException(e);
            }
        }
    }

    @Override
    public Object postProcessAfterSetCache(CacheMethod invocation, Object value, AbstractCache cache) {
        if (invocation.getMethod().isAnnotationPresent(CacheHandler.class)) {
            CacheHandler handler = invocation.getMethod().getDeclaredAnnotation(CacheHandler.class);
            try {
                CachePostProcess process = (CachePostProcess) PostProcessFactory.acpps.getOrDefault(handler.value(), (CachePostProcess) InstanceUtils.newInstance(handler.value()));
                if (handler.overall()) {
                    PostProcessFactory.overall.add(process);
                    for (PostProcess postProcess : PostProcessFactory.overall) {
                        if (postProcess instanceof CachePostProcess)
                            value = ((CachePostProcess) postProcess).postProcessAfterSetCache(invocation, value, cache);
                    }
                    return value;
                } else {
                    return process.postProcessAfterSetCache(invocation, value, cache);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                // 初始化实例失败
                throw new InitException(e);
            }
        }
        return value;
    }

    @Override
    public boolean postProcessPreSetCache(CacheMethod invocation, Object value, Timer timer) {
        if (invocation.getMethod().isAnnotationPresent(CacheHandler.class)) {
            CacheHandler handler = invocation.getMethod().getDeclaredAnnotation(CacheHandler.class);
            try {
                CachePostProcess process = (CachePostProcess) PostProcessFactory.acpps.getOrDefault(handler.value(), (CachePostProcess) InstanceUtils.newInstance(handler.value()));
                if (handler.overall()) {
                    PostProcessFactory.overall.add(process);
                    boolean preRes = true;
                    for (PostProcess postProcess : PostProcessFactory.overall) {
                        if (postProcess instanceof CachePostProcess)
                            preRes = ((CachePostProcess) postProcess).postProcessPreSetCache(invocation, value, timer);
                    }
                    return preRes;
                } else {
                    return process.postProcessPreSetCache(invocation, value, timer);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                // 初始化实例失败
                throw new InitException(e);
            }
        }
        return true;
    }
}
